/*
	1： 转发给客户端 webSocket
*/

package WsPorxy

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"net/http"
	//"strings"
	"math"
	"time"
	"utils"

	"golang.org/x/net/websocket"
)

type WebSocketControl struct {
	TargetWsip    string
	PoryxPort     string
	mbMaintenance bool
	mstrWhMeg     string
	mWsTcp        *WsToTcp
	mWs           *websocket.Conn
	mSer          *http.Server
	m_NetBuf      *utils.CTCPSocket //msg 解析
	mSocketList   *utils.SafeQueue
	mCurNumber    uint64
	//mIp           string
}

func (this *WebSocketControl) Echo(ws *websocket.Conn) {
	var err error

	utils.SysLog.PutLineAsLog(fmt.Sprintf("New Clinet Connect Links:@%s ", ws.RemoteAddr()))

	if this.mCurNumber > math.MaxUint64 {
		this.mCurNumber = 0
	}
	this.mCurNumber++
	fmt.Println(fmt.Sprintf("TargetWsip : %s this.mCurNumber = %d", this.TargetWsip, this.mCurNumber))
	//this.mIp = ws.Config().Origin.Host //strings.Split(ws.RemoteAddr().String(), ":")[0]

	if this.mbMaintenance == true {

		CmdWhMeg := new(utils.CMD_GP_OperateFailure)
		CmdWhMeg.LResultCode = 0

		if this.mstrWhMeg == "" {
			this.mstrWhMeg = "本平台目前正在维护中带来不便尽情谅解"
		}

		Msg := utils.UTF8to16(this.mstrWhMeg) //
		copy(CmdWhMeg.SzDescribeString[:], Msg[:])
		//CmdWhMeg.Timestamp = uint32(time.Now().Unix())

		buf_w := new(bytes.Buffer)
		binary.Write(buf_w, binary.LittleEndian, CmdWhMeg)
		this.m_NetBuf.SendData(utils.MDM_GP_LOGON, utils.SUB_GP_LOGON_FAILURE, buf_w.Bytes(), uint16(binary.Size(CmdWhMeg)), ws, 0, "--")
		ws.Close()
		return
	}

	var cliletScoket *WsToTcp
	if this.mSocketList.Size() > 0 {
		cliletScoket = this.mSocketList.Pop().(*WsToTcp)
		fmt.Println("socket复用")
	} else {
		cliletScoket = MakeNewWsToTcp(this)
		fmt.Println(fmt.Sprintf("socket新建 :[%s] ", utils.GetNowTime()))
	}

	//构造对象
	//wsTcp := MakeNewWsToTcp(this)
	this.mWsTcp = cliletScoket
	this.mWs = ws
	//创建链接
	if cliletScoket.ConnentFoxServer(this.TargetWsip, ws) == false {
		cliletScoket.Close()
	} else {
		//增加验证
		cliletScoket.ConnectVerifcation()
	}

	for {

		//设置超时
		if err := ws.SetReadDeadline(time.Now().Add(time.Second * 60)); err != nil {
			fmt.Println(fmt.Sprintf("time out"))
			break
		}
		var reply string
		if err = websocket.Message.Receive(ws, &reply); err != nil {
			cliletScoket.PrintLog("", fmt.Sprintf("Clinet ShutDown @%s err:%s", ws.RemoteAddr(), err.Error()))
			cliletScoket.Close()
			fmt.Println("Close....")
			break
		}
		cliletScoket.SendData([]byte(reply))

		fmt.Println("Recv a message!")
	}

	fmt.Println(fmt.Sprintf("Server Clear Clinet To Mark  this.TargetWsip = %s", this.TargetWsip))
	this.mSocketList.Push(cliletScoket)
	fmt.Println(fmt.Sprintf("this.mSocketList = %d this.TargetWsip = %s", this.mSocketList.Size(), this.TargetWsip))

}

func (this *WebSocketControl) NewWsServer() {

	fmt.Println(fmt.Sprintf("Listen Port:%s", this.PoryxPort))
	fmt.Println(fmt.Sprintf("target Port:%s", this.TargetWsip))

	http.Handle("/"+this.PoryxPort, websocket.Handler(this.Echo)) //

	mSer := &http.Server{
		Addr:    ":" + this.PoryxPort,
		Handler: nil,
	}
	this.mSer = mSer
	if err := this.mSer.ListenAndServe(); err != nil {
		utils.SysLog.PutLineAsLog(fmt.Sprintf(":%s", err))
	}
}

//维护公告
func (this *WebSocketControl) MaintenanceMessage(msg string) {
	this.mbMaintenance = true
	this.mstrWhMeg = msg
}

//取消维护公告
func (this *WebSocketControl) CancelMaintenanceMessage() {
	this.mbMaintenance = false
}

//取消代理
func (this *WebSocketControl) CancelProxy() {
	fmt.Println("准备撤销代理")
	if this.mWs != nil {
		this.mWs.Close()
	}

	if this.mWsTcp != nil {
		this.mWsTcp.Close()
	}

	fmt.Println("shutdown server")
	this.mSer.Shutdown(nil)
}

func NewWebSocketControl(porxyport, targetip string) *WebSocketControl {
	this := &WebSocketControl{
		TargetWsip:    targetip,
		PoryxPort:     porxyport,
		mbMaintenance: false,
		mWsTcp:        nil,
		mWs:           nil,
		mCurNumber:    0,
		mSocketList:   utils.MakeNewSafeQueue(100000),
	}

	this.m_NetBuf = utils.MarkNewTCPScoket("ProxySercer To CoreServer:", nil)

	return this
}

func ListenWebSocket(porxyport, targetip string) {
	this := NewWebSocketControl(porxyport, targetip)
	if this != nil {
		this.NewWsServer()
	}
}
